package com.xframe.xdal.core.serialize;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.xframe.xdal.core.constant.ErrorCode;
import com.xframe.xdal.core.constant.ErrorMsg;
import com.xframe.xdal.core.exception.DalFrameException;
import com.xframe.xdal.core.model.mapping.ITableInfo;
import com.xframe.xdal.core.serialize.proc.ISerializeProc;
import com.xframe.xdal.core.util.StringUtil;
import com.xframe.xdal.core.util.XReflect;
import org.apache.commons.collections4.map.HashedMap;

import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

public class BaseJsonSer implements IJSONSer {

    private static final Map<String, String> jsonMap = new ConcurrentHashMap<>();

    @Override
    public <T> T toObject(String json, Class<?> dataType) {
        return (T) JSON.parseObject(json, dataType);
    }

    @Override
    public <T> T toObject(String json, Class<?> dataType, ITableInfo tableInfo) {
        return (T) JSON.parseObject(json, dataType);
    }

    @Override
    public String toJson(Object bean) {
        if (bean == null) {
            return null;
        }
        //return StringUtil.toJSONString(bean);
//        return JSON.toJSONString(bean);
        return JSONUtil.toJsonStr(bean);
    }

    /**
     * 根据配置文件来序列化对象返回JSON
     *
     * @param bean      被序列化的对象
     * @param tableInfo 表单结构对象
     * @param language  当前的语言
     * @param queryKey  外部查询关键字
     * @param ver       当前的附加版本
     * @throws IOException
     */
    @Override
    public String toJson(Object bean, ITableInfo tableInfo, String language, String queryKey, String ver) {
        Object jsonObj = toJsonObj(bean, tableInfo, language, queryKey, ver);
        return toJson(jsonObj);
    }


    private List<Object> toJsonObj(List<Object> beans, ITableInfo tableInfo, String language, String queryKey, String ver) {
        if (CollectionUtil.isEmpty(beans)) {
            return null;
        }
        List<Object> list = new CopyOnWriteArrayList<>();
        beans.forEach(b -> {
            Map<String, Object> dictMap = new ConcurrentHashMap<>(64);
            getBeanDict(b, tableInfo.getCode(), queryKey, language, ver, dictMap);
            if (CollectionUtil.isNotEmpty(dictMap)) {
                list.add(dictMap);
            }else {
                list.add(b);
            }

        });
        if (CollectionUtil.isNotEmpty(list)) {
            return list;
        }
        return beans;
    }

    /**
     * 根据配置文件来序列化对象返回
     *
     * @param bean      被序列化的对象
     * @param tableInfo 表单结构对象
     * @param language  当前的语言
     * @param queryKey  外部查询关键字
     * @param ver       当前的附加版本
     */
    @Override
    public Object toJsonObj(Object bean, ITableInfo tableInfo, String language, String queryKey, String ver) {
        if (bean == null) {
            return null;
        }
        if (tableInfo == null) {
            throw new DalFrameException(ErrorCode.TABLEINFO_NO_FIND, ErrorMsg.TABLEINFO_NO_FIND_MSG);
        }
        if (StringUtil.isEmpty(language)) {
            language = "cn";
        }
        if (StringUtil.isEmpty(queryKey)) {
            queryKey = "default";
        }
        if (StringUtil.isEmpty(ver)) {
            ver = "v1";
        }
        String fileName = tableInfo.getCode();
        Map<String, Object> dictMap = new ConcurrentHashMap<>(64);
        if (Collection.class.isAssignableFrom(bean.getClass())) {
            return this.toJsonObj((List) bean, tableInfo, language, queryKey, ver);
        } else {
            getBeanDict(bean, fileName, queryKey, language, ver, dictMap);
            if (CollectionUtil.isNotEmpty(dictMap)) {
                return dictMap;
            }
        }
        return bean;
    }

    /**
     * @param bean      对象
     * @param modelCode 模型编码
     * @param language  语言
     * @param queryKey  查询类型
     * @param ver       版本
     * @param dictMap   处理后对象
     */
    private void getBeanDict(Object bean, String modelCode, String queryKey, String language, String ver, Map<String, Object> dictMap) {
        JsonConfig jsonConfig = JsonConfigContainer.getConfigContainer().getJsonConfig(language,ver,modelCode,queryKey);
        if (jsonConfig != null) {
            List<JsonModel> jsonModelList = jsonConfig.getJsonModelList();
            //parallelStream
            jsonModelList.parallelStream().forEach(model -> {
                String name = model.getName();
                String mapName = model.getMapName();
                if (model.isRefModel()) {
                    //处理关联对象信息
                    Object subobject = XReflect.getFieldValue(bean, name);
                    if (BeanUtil.isNotEmpty(subobject)) {
                        if (model.isRefObj()) {
                            Map sbuMap = new ConcurrentHashMap<String, Object>(64);
                            dictMap.put(mapName, sbuMap);
                            getBeanDict(subobject, model.getRefModelCode(), model.getFlag(), language, ver, sbuMap);
                        } else if(model.isRefArray()) {
                            List subList = new CopyOnWriteArrayList();
                            dictMap.put(mapName, subList);
                            if (Collection.class.isAssignableFrom(subobject.getClass())) {
                                Collection subJsonModelList = (Collection) subobject;
                                subJsonModelList.stream().forEach(b -> {
                                    Map subMap = new ConcurrentHashMap<String, Object>(64);
                                    subList.add(subMap);
                                    getBeanDict(b, model.getRefModelCode(), model.getFlag(), language, ver, subMap);
                                });
                            }
                        }
                    }else {
                        if (model.isRefObj()) {
                            dictMap.put(mapName, new HashMap<>(0));
                        }
                        if(model.isRefArray()){
                            dictMap.put(mapName, new Object[0]);
                        }
                    }
                } else {
                    Object attrValue = XReflect.getFieldValue(bean, name);
                    if(model.hasSerializeProc()) {
                        ISerializeProc serializeProc = model.getSerializeProc();
                        if (serializeProc != null) {
                            attrValue = serializeProc.procValue(bean, attrValue, model.getClassArgs(), language);
                            if(attrValue == null){
                                dictMap.put(mapName, StringUtil.EMPTY);
                            }else {
                                dictMap.put(mapName, attrValue);
                            }
                        }
                    }else {
                        if (BeanUtil.isNotEmpty(attrValue)) {
                            dictMap.put(mapName, attrValue.toString());
                        }else {
                            dictMap.put(mapName, StringUtil.EMPTY);
                        }
                    }


                }
            });
        }
    }



}
